package com.chagee.channel.server.event.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.http.HttpException;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.ocr_api20210707.models.*;
import com.aliyun.teautil.models.RuntimeOptions;
import com.chagee.channel.api.bo.ocr.*;
import com.chagee.channel.common.exception.BizException;
import com.chagee.channel.server.config.OcrConfig;
import com.chagee.channel.server.event.service.OcrService;
import com.chagee.channel.server.util.HttpUtils;
import com.chagee.channel.server.util.LocalDateTimeUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;

/**
 * ocr识别
 *
 * @author: chang.jiawei
 * @date: 2024/01/18
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class OcrServiceImpl implements OcrService {

    private final OcrConfig ocrConfig;

    @Override
    public FoodOperationLicenseOcrDTO ocrFoodOperationLicense(String fileUrl) {
        RecognizeFoodManageLicenseRequest recognizeFoodManageLicenseRequest = new RecognizeFoodManageLicenseRequest().setUrl(fileUrl);
        checkFileUrl(fileUrl, (bytes) -> recognizeFoodManageLicenseRequest.setUrl(null).setBody(new ByteArrayInputStream(bytes)));
        RuntimeOptions runtime = new RuntimeOptions();
        try {
            RecognizeFoodManageLicenseResponse response = ocrConfig.client().recognizeFoodManageLicenseWithOptions(recognizeFoodManageLicenseRequest, runtime);
            return JSONObject.parseObject(JSONObject.parseObject(response.getBody().getData()).get("data").toString(), FoodOperationLicenseOcrDTO.class);
        } catch (Exception error) {
            log.error("识别食品经营许可证失败!", error);
            throw new BizException("识别食品经营许可证失败");
        }
    }

    /**
     * 检查fileUrl是否包含指定domain，是则将fileUrl转bytes
     * @param fileUrl
     * @param consumer
     */
    private void checkFileUrl(String fileUrl, Consumer<byte[]> consumer) {
        if(BooleanUtil.isTrue(ocrConfig.getCheckBucket())){
            if(CollectionUtil.isNotEmpty(ocrConfig.getCheckBucketDomains())){
                Optional<String> optional = ocrConfig.getCheckBucketDomains().stream().filter(domain -> fileUrl.contains(domain)).findAny();
                if(optional.isPresent()){
                    log.info("发现需要转换的fileUrl: {}", fileUrl);
                    // 如果fileUrl包含指定的domain，则下载文件。
                    byte[] bytes = HttpUtils.downloadBytes(fileUrl);
                    consumer.accept(bytes);
                }
            }
        }
    }

    @Override
    public BusinessLicenseOcrDTO ocrBusinessLicense(String fileUrl) {
        RecognizeBusinessLicenseRequest request = new RecognizeBusinessLicenseRequest().setUrl(fileUrl);
        log.info("识别营业执照参数:{}", JSON.toJSONString(request));
        checkFileUrl(fileUrl, (bytes) -> request.setUrl(null).setBody(new ByteArrayInputStream(bytes)));
        RuntimeOptions runtime = new RuntimeOptions();
        try {
            RecognizeBusinessLicenseResponse response = ocrConfig.client().recognizeBusinessLicenseWithOptions(request, runtime);
            JSONObject jsonObject = (JSONObject) JSONObject.parseObject(response.getBody().getData()).get("data");
            log.info("识别营业执照图片解析:{}",jsonObject);
            LocalDate localDate= LocalDateTimeUtil.toLocalDate((String) jsonObject.get("RegistrationDate"));
            if(localDate !=null) {
                jsonObject.put("RegistrationDate", localDate);
            }
            return JSONObject.parseObject(jsonObject.toString(), BusinessLicenseOcrDTO.class);
        } catch (Exception error) {
            log.error("识别营业执照失败!", error);
            throw new BizException("识别营业执照失败");
        }
    }

    @Override
    public BankAccountLicenseOcrDTO ocrBankAccountLicense(String fileUrl) {
        RecognizeBankAccountLicenseRequest request = new RecognizeBankAccountLicenseRequest().setUrl(fileUrl);
        checkFileUrl(fileUrl, (bytes) -> request.setUrl(null).setBody(new ByteArrayInputStream(bytes)));
        RuntimeOptions runtime = new RuntimeOptions();
        try {
            RecognizeBankAccountLicenseResponse response = ocrConfig.client().recognizeBankAccountLicenseWithOptions(request, runtime);
            return JSONObject.parseObject(JSONObject.parseObject(response.getBody().getData()).get("data").toString(), BankAccountLicenseOcrDTO.class);
        } catch (Exception error) {
            log.error("识别银行开户许可证失败!", error);
            throw new BizException("识别银行开户许可证失败");
        }
    }

    @Override
    public IdCardFrontDTO ocrIdCardFront(String frontUrl) {
        RuntimeOptions runtime = new RuntimeOptions();
        RecognizeIdcardRequest request = new RecognizeIdcardRequest().setUrl(frontUrl);
        checkFileUrl(frontUrl, (bytes) -> request.setUrl(null).setBody(new ByteArrayInputStream(bytes)));
        try {
            RecognizeIdcardResponse response = ocrConfig.client().recognizeIdcardWithOptions(request, runtime);
            log.info("ocr idcard front : " + response.getBody().getData());
            JSONObject faceData = JSONObject.parseObject(response.getBody().getData())
                    .getJSONObject("data")
                    .getJSONObject("face")
                    .getJSONObject("data");
            IdCardFrontDTO dto = new IdCardFrontDTO();
            dto.setIdCardNo(faceData.getString("idNumber"));
            dto.setName(faceData.getString("name"));
            dto.setBirth(faceData.getString("birthDate"));
            dto.setNation(faceData.getString("ethnicity"));
            dto.setAddress(faceData.getString("address"));
            dto.setGender(faceData.getString("sex"));
            return dto;
        } catch (Exception e) {
            log.error("识别身份证正面失败!", e);
            throw new BizException("识别身份证正面失败");
        }
    }

    @Override
    public IdCardBackDTO ocrIdCardBack(String backUrl) {
        RuntimeOptions runtime = new RuntimeOptions();
        RecognizeIdcardRequest request = new RecognizeIdcardRequest().setUrl(backUrl);
        checkFileUrl(backUrl, (bytes) -> request.setUrl(null).setBody(new ByteArrayInputStream(bytes)));
        try {
            RecognizeIdcardResponse response = ocrConfig.client().recognizeIdcardWithOptions(request, runtime);
            log.info("ocr idcard back : " + response.getBody().getData());
            JSONObject backData = JSONObject.parseObject(response.getBody().getData())
                    .getJSONObject("data")
                    .getJSONObject("back")
                    .getJSONObject("data");
            IdCardBackDTO dto = new IdCardBackDTO();
            dto.setValidPeriod(backData.getString("validPeriod"));
            dto.setIssueAuthority(backData.getString("issueAuthority"));
            return dto;
        } catch (Exception e) {
            log.error("识别身份证背面失败!", e);
            throw new BizException("识别身份证背面失败");
        }
    }

    @Override
    public BankCardDTO ocrBankCard(String fileUrl) {
        RecognizeBankCardRequest request = new RecognizeBankCardRequest().setUrl(fileUrl);
        checkFileUrl(fileUrl, (bytes) -> request.setUrl(null).setBody(new ByteArrayInputStream(bytes)));
        try {
            RecognizeBankCardResponse response = ocrConfig.client().recognizeBankCard(request);
            return JSONObject.parseObject(JSONObject.parseObject(response.getBody().getData()).get("data").toString(), BankCardDTO.class);
        } catch (Exception error) {
            log.error("识别银行卡失败!", error);
            throw new BizException("识别银行卡失败");
        }
    }
    @Override
    public HKBusinessLicenseOcrDTO ocrHKBusinessLicense(String fileUrl) throws JsonProcessingException {
        HKBusinessLicenseOcrDTO hkBusinessLicenseOcrDTO=new HKBusinessLicenseOcrDTO();
        String host = "https://xianggyyzz.market.alicloudapi.com";
        String path = "/ocrservice/multiBlicenseHk";
        String method = "POST";
        String appcode = "48e32e1593b04b7d940112f3c8d93314\n";
        Map<String, String> headers = new HashMap<String, String>();
        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + appcode);
        //根据API的要求，定义相对应的Content-Type
        headers.put("Content-Type", "application/json; charset=UTF-8");
        headers.put(HttpHeaders.REFERER, HttpUtils.getReferer());
        Map<String, String> querys = new HashMap<String, String>();
        String body = "{\"img\":\"\",\"url\":\"\"}";

        // 使用 Jackson 解析 JSON
        ObjectMapper mapper = new ObjectMapper();
        JsonNode jsonNode = mapper.readTree(body);

        // 修改字段值
        ((ObjectNode) jsonNode).put("url", fileUrl);

        // 转换回字符串
        String bodys = mapper.writeValueAsString(jsonNode);
        try {

            HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
            log.info("ocrHKBusinessLicense.response:{}",response.toString());
//            log.info("ocrHKBusinessLicense.EntityUtils:{}", EntityUtils.toString(response.getEntity()));
            String json=EntityUtils.toString(response.getEntity());
            log.info("ocrHKBusinessLicense.EntityUtils.json:{}",json);
//            String json = JSONUtil.toJsonStr(response.getEntity());
//            log.info("ocrHKBusinessLicense.EntityUtils.json:{}",json);
            // 将JSON字符串解析为JSONObject
            JSONObject jsonObject = JSONObject.parseObject(json);
            log.info("ocrHKBusinessLicense.jsonObject:{}",jsonObject);

            // 获取"data"部分
            JSONObject dataObject = jsonObject.getJSONObject("data");
            String type = jsonObject.getString("type");

            // 输出"data"部分
            log.info("ocrHKBusinessLicense.Data部分:{}",dataObject);
            log.info("ocrHKBusinessLicense.type部分:{}",type);

            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");


            //
            hkBusinessLicenseOcrDTO.setCompanyNameCN(dataObject.getString("公司名称-中文"));
            hkBusinessLicenseOcrDTO.setCompanyNameEN(dataObject.getString("公司名称-英文"));
//            hkBusinessLicenseOcrDTO.setSubCompanyNameCN(dataObject.getString("分公司名称-中文"));
//            hkBusinessLicenseOcrDTO.setSubCompanyNameEN(dataObject.getString("分公司名称-英文"));
//            阿里云不支持，置为空
            hkBusinessLicenseOcrDTO.setSubCompanyNameCN("");
            hkBusinessLicenseOcrDTO.setSubCompanyNameEN("");
            hkBusinessLicenseOcrDTO.setBusinessAddress(dataObject.getString("地址"));
            hkBusinessLicenseOcrDTO.setCompanyType(dataObject.getString("业务性质"));
            hkBusinessLicenseOcrDTO.setBusinessType(type);
            hkBusinessLicenseOcrDTO.setEffectiveDate(LocalDate.parse(dataObject.getString("生效日期"), formatter));
            hkBusinessLicenseOcrDTO.setLegalStatus(dataObject.getString("法律地位"));
            hkBusinessLicenseOcrDTO.setLevyFee(dataObject.getString("征费"));
            hkBusinessLicenseOcrDTO.setRegistrationFee(dataObject.getString("登记费"));
            hkBusinessLicenseOcrDTO.setTerminationDate(LocalDate.parse(dataObject.getString("终止日期"), formatter));
            hkBusinessLicenseOcrDTO.setTotalCost(dataObject.getString("费用合计"));
            hkBusinessLicenseOcrDTO.setRegistrationNumber(dataObject.getString("登记号码"));
            return hkBusinessLicenseOcrDTO;
//            return null;
        } catch (Exception error) {
            log.error("识别香港营业执照失败!", error);
            throw new BizException("识别香港营业执照失败");
        }

    }


}
